home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH21 / INT17.ASM next >
Encoding:
Assembly Source File  |  1994-07-25  |  10.8 KB  |  377 lines

  1. ; INT17.ASM
  2. ;
  3. ; A short passive TSR that replaces the BIOS' int 17h handler.
  4. ; This routine demonstrates the function of each of the int 17h
  5. ; functions that a standard BIOS would provide.
  6. ;
  7. ; Note that this code does not patch into int 2Fh (multiplex interrupt)
  8. ; nor can you remove this code from memory except by rebooting.
  9. ; If you want to be able to do these two things (as well as check for
  10. ; a previous installation), see the chapter on resident programs.  Such
  11. ; code was omitted from this program because of length constraints.
  12. ;
  13. ;
  14. ; cseg and EndResident must occur before the standard library segments!
  15.  
  16. cseg        segment    para public 'code'
  17. cseg        ends
  18.  
  19. ; Marker segment, to find the end of the resident section.
  20.  
  21. EndResident    segment    para public 'Resident'
  22. EndResident    ends
  23.  
  24.         .xlist
  25.         include     stdlib.a
  26.         includelib    stdlib.lib
  27.         .list
  28.  
  29.  
  30. byp        equ    <byte ptr>
  31.  
  32. cseg        segment    para public 'code'
  33.         assume    cs:cseg, ds:cseg
  34.  
  35. OldInt17    dword    ?
  36.  
  37.  
  38. ; BIOS variables:
  39.  
  40. PrtrBase    equ    8
  41. PrtrTimeOut    equ    78h
  42.  
  43.  
  44.  
  45.  
  46. ; This code handles the INT 17H operation.  INT 17H is the BIOS routine
  47. ; to send data to the printer and report on the printer's status.  There
  48. ; are three different calls to this routine, depending on the contents
  49. ; of the AH register.  The DX register contains the printer port number.
  50. ;
  51. ; DX=0 -- Use LPT1:
  52. ; DX=1 -- Use LPT2:
  53. ; DX=2 -- Use LPT3:
  54. ; DX=3 -- Use LPT4:
  55. ;
  56. ; AH=0 -- Print the character in AL to the printer.  Printer status is
  57. ;      returned in AH.  If bit #0 = 1 then a timeout error occurred.
  58. ;
  59. ; AH=1 -- Initialize printer.  Status is returned in AH.
  60. ;
  61. ; AH=2 -- Return printer status in AH.
  62. ;
  63. ;
  64. ; The status bits returned in AH are as follows:
  65. ;
  66. ;  Bit    Function            Non-error values
  67. ;  ---   --------------------------     ----------------
  68. ;   0     1=time out error            0
  69. ;   1       unused                x
  70. ;   2       unused                x
  71. ;   3     1=I/O error                0
  72. ;   4     1=selected, 0=deselected.        1
  73. ;   5     1=out of paper            0
  74. ;   6     1=acknowledge                x
  75. ;   7     1=not busy                x
  76. ;
  77. ; Note that the hardware returns bit 3 with zero if an error has occurred,
  78. ; with one if there is no error.  The software normally inverts this bit
  79. ; before returning it to the caller.
  80. ;
  81. ;
  82. ; Printer port hardware locations:
  83. ;
  84. ; There are three ports used by the printer hardware:
  85. ;
  86. ; PrtrPortAdrs   ---  Output port where data is sent to printer (8 bits).
  87. ; PrtrPortAdrs+1 ---  Input port where printer status can be read (8 bits).
  88. ; PrtrPortAdrs+2 ---  Output port where control information is sent to the
  89. ;              printer.
  90. ;
  91. ; Data output port- 8-bit data is transmitted to the printer via this port.
  92. ;
  93. ; Input status port:
  94. ;            bit 0: unused.
  95. ;            bit 1: unused.
  96. ;            bit 2: unused.
  97. ;
  98. ;            bit 3: -Error, normally this bit means that the
  99. ;                printer has encountered an error.  However,
  100. ;                with the P101 installed this is a data
  101. ;                return line for the keyboard scan.
  102. ;
  103. ;            bit 4: +SLCT, normally this bit is used to determine
  104. ;                if the printer is selected or not.  With the
  105. ;                P101 installed this is a data return
  106. ;                line for the keyboard scan.
  107. ;
  108. ;            bit 5: +PE, a 1 in this bit location means that the
  109. ;                printer has detected the end of paper.  On
  110. ;                many printer ports, this bit has been found
  111. ;                to be inoperative.
  112. ;
  113. ;            bit 6: -ACK, A zero in this bit position means that
  114. ;                the printer has accepted the last character
  115. ;                and is ready to accept another.  This bit
  116. ;                is not normally used by the BIOS as bit 7
  117. ;                also provides this function (and more).
  118. ;
  119. ;            bit 7: -Busy, When this signal is active (0) the
  120. ;                printer is busy and cannot accept data.
  121. ;                When this bit is set to one, the printer
  122. ;                can accept another character.
  123. ;
  124. ;
  125. ;
  126. ; Output control port:
  127. ;
  128. ;             Bit 0: +Strobe, A 0.5 us (minimum) active high pulse
  129. ;                on this bit clocks the data latched into the
  130. ;                printer data output port to the printer.
  131. ;
  132. ;            Bit 1: +Auto FD XT - A 1 stored at this bit causes
  133. ;                the printer to line feed after a line is
  134. ;                printed.  On some printer interfaces (e.g.,
  135. ;                the Hercules Graphics Card) this bit is
  136. ;                inoperative.
  137. ;
  138. ;            Bit 2: -INIT, a zero on this bit (for a minimum of
  139. ;                50 us) will cause the printer to (re)init-
  140. ;                ialize itself.
  141. ;
  142. ;            Bit 3: +SLCT IN, a one in this bit selects the
  143. ;                printer.  A zero will cause the printer to
  144. ;                go off-line.
  145. ;
  146. ;            Bit 4: +IRQ ENABLE, a one in this bit position
  147. ;                allows an interrupt to occur when -ACK
  148. ;                changes from one to zero.
  149. ;
  150. ;            Bit 5: Direction control on BI-DIR port. 0=output,
  151. ;                   1=input.
  152. ;            Bit 6: reserved, must be zero.
  153. ;            Bit 7: reserved, must be zero.
  154.  
  155. MyInt17        proc    far
  156.         assume    ds:nothing
  157.  
  158.         push    ds
  159.         push    bx
  160.         push    cx
  161.         push    dx
  162.  
  163.         mov    bx, 40h            ;Point DS at BIOS vars.
  164.         mov    ds, bx
  165.  
  166.         cmp    dx, 3            ;Must be LPT1..LPT4.
  167.         ja    InvalidPrtr
  168.  
  169.         cmp    ah, 0        ;Branch to the appropriate code for
  170.         jz    PrtChar        ; the printer function
  171.         cmp    ah, 2
  172.         jb    PrtrInit
  173.         je    PrtrStatus
  174.  
  175. ; If they passed us an opcode we don't know about, just return.
  176.  
  177. InvalidPrtr:    jmp    ISR17Done
  178.  
  179.  
  180.  
  181. ; Initialize the printer by pulsing the init line for at least 50 us.
  182. ; The delay loop below will delay well beyond 50 usec even on the fastest
  183. ; machines.
  184.  
  185. PrtrInit:    mov    bx, dx            ;Get printer port value.
  186.         shl    bx, 1            ;Convert to byte index.
  187.         mov    dx, PrtrBase[bx]    ;Get printer base address.
  188.         test    dx, dx            ;Does this printer exist?
  189.         je    InvalidPrtr        ;Quit if no such printer.
  190.         add    dx, 2            ;Point dx at control reg.
  191.         in    al, dx            ;Read current status.
  192.         and    al, 11011011b        ;Clear INIT/BIDIR bits.
  193.         out    dx, al            ;Reset printer.
  194.         mov    cx, 0            ;This will produce at least
  195. PIDelay:    loop    PIDelay            ; a 50 usec delay.
  196.         or    al, 100b        ;Stop resetting printer.
  197.         out    dx, al
  198.         jmp    ISR17Done
  199.  
  200.  
  201. ; Return the current printer status.  This code reads the printer status
  202. ; port and formats the bits for return to the calling code.
  203.  
  204. PrtrStatus:    mov    bx, dx            ;Get printer port value.
  205.         shl    bx, 1            ;Convert to byte index.
  206.         mov    dx, PrtrBase[bx]    ;Base address of printer port.
  207.         mov    al, 00101001b        ;Dflt: every possible error.
  208.         test    dx, dx            ;Does this printer exist?
  209.         je    InvalidPrtr        ;Quit if no such printer.
  210.         inc    dx            ;Point at status port.
  211.         in    al, dx            ;Read status port.
  212.         and    al, 11111000b        ;Clear unused/timeout bits.
  213.         jmp    ISR17Done
  214.  
  215.  
  216.  
  217. ; Print the character in the accumulator!
  218.  
  219. PrtChar:        mov    bx, dx
  220.         mov    cl, PrtrTimeOut[bx]    ;Get time out value.
  221.         shl    bx, 1            ;Convert to byte index.
  222.         mov    dx, PrtrBase[bx]    ;Get Printer port address
  223.         or    dx, dx            ;Non-nil pointer?
  224.         jz    NoPrtr2            ; Branch if a nil ptr
  225.  
  226. ; The following code checks to see if an acknowlege was received from
  227. ; the printer.  If this code waits too long, a time-out error is returned.
  228. ; Acknowlege is supplied in bit #7 of the printer status port (which is
  229. ; the next address after the printer data port).
  230.  
  231.         push    ax
  232.         inc    dx            ;Point at status port
  233.         mov    bl, cl            ;Put timeout value in bl
  234.         mov    bh, cl            ; and bh.
  235. WaitLp1:    xor    cx, cx            ;Init count to 65536.
  236. WaitLp2:    in    al, dx            ;Read status port
  237.         mov    ah, al            ;Save status for now.
  238.         test    al, 80h            ;Printer acknowledge?
  239.         jnz    GotAck            ;Branch if acknowledge.
  240.         loop    WaitLp2            ;Repeat 65536 times.
  241.         dec    bl            ;Decrement time out value.
  242.         jnz    WaitLp1            ;Repeat 65536*TimeOut times.
  243.  
  244. ; See if the user has selected no timeout:
  245.  
  246.         cmp     bh, 0
  247.         je    WaitLp1
  248.  
  249. ; TIMEOUT ERROR HAS OCCURRED!
  250. ;
  251. ; A timeout - I/O error is returned to the system at this point.
  252. ; Either we fall through to this point from above (time out error) or
  253. ; the referenced printer port doesn't exist.  In any case, return an error.
  254.  
  255. NoPrtr2:    or    ah, 9            ;Set timeout-I/O error flags
  256.         and    ah, 0F9h        ;Turn off unused flags.
  257.         xor    ah, 40h            ;Flip busy bit.
  258.  
  259. ; Okay, restore registers and return to caller.
  260.  
  261.         pop    cx            ;Remove old ax.
  262.         mov    al, cl            ;Restore old al.
  263.         jmp    ISR17Done
  264.  
  265.  
  266. ; If the printer port exists and we've received an acknowlege, then it's
  267. ; okay to transmit data to the printer.  That job is handled down here.
  268.  
  269. GotAck:        mov    cx, 16            ;Short delay if crazy prtr
  270. GALp:        loop    GALp            ; needs hold time after ack.
  271.         pop    ax            ;Get char to output and
  272.         push    ax            ; save again.
  273.         dec    dx            ;Point DX at printer port.
  274.         pushf                ;Turn off interrupts for now.
  275.         cli
  276.         out    dx, al            ;Output data to the printer.
  277.  
  278. ; The following short delay gives the data time to travel through the
  279. ; parallel lines.  This makes sure the data arrives at the printer before
  280. ; the strobe (the times can vary depending upon the capacitance of the
  281. ; parallel cable's lines).
  282.  
  283.         mov    cx, 16            ;Give data time to settle
  284. DataSettleLp:    loop    DataSettleLp        ; before sending strobe.
  285.  
  286. ; Now that the data has been latched on the printer data output port, a
  287. ; strobe must be sent to the printer.  The strobe line is connected to
  288. ; bit zero of the printer port.  Also note that this clears bit 5 of the
  289. ; control port.  This ensures that the port continues to operate as an
  290. ; output port if it is a bidirectional device.  This code also clears bits
  291. ; six and seven which IBM claims should be left zero.
  292.  
  293.         inc    dx            ;Point DX at the printer
  294.         inc    dx            ; control output port.
  295.         in    al, dx            ;Get current control bits.
  296.         and    al, 01eh        ;Force strobe line to zero and
  297.         out    dx, al            ; make sure it's an output port.
  298.  
  299.  
  300.         mov    cx, 16            ;Short delay to allow data
  301. Delay0:        loop    Delay0            ; to become good.
  302.  
  303.         or    al, 1            ;Send out the (+) strobe.
  304.         out    dx, al            ;Output (+) strobe to bit 0
  305.  
  306.         mov    cx, 16            ;Short delay to lengthen strobe
  307. StrobeDelay:    loop    StrobeDelay
  308.  
  309.         and    al, 0FEh        ;Clear the strobe bit.
  310.         out    dx, al            ;Output to control port.
  311.         popf                ;Restore interrupts.
  312.  
  313.         pop    dx            ;Get old AX value
  314.         mov    al, dl            ;Restore old AL value
  315.  
  316. ISR17Done:    pop    dx
  317.         pop    cx
  318.         pop    bx
  319.         pop    ds
  320.         iret
  321. MyInt17        endp
  322.  
  323.  
  324.  
  325.  
  326.  
  327. Main        proc
  328.  
  329.         mov    ax, cseg
  330.         mov    ds, ax
  331.  
  332.         print
  333.         byte    "INT 17h Replacement",cr,lf
  334.         byte    "Installing....",cr,lf,0
  335.  
  336. ; Patch into the INT 17 interrupt vector.  Note that the
  337. ; statements above have made cseg the current data segment,
  338. ; so we can store the old INT 17 value directly into
  339. ; the OldInt17 variable.
  340.  
  341.         cli                ;Turn off interrupts!
  342.         mov    ax, 0
  343.         mov    es, ax
  344.         mov    ax, es:[17h*4]
  345.         mov    word ptr OldInt17, ax
  346.         mov    ax, es:[17h*4 + 2]
  347.         mov    word ptr OldInt17+2, ax
  348.         mov    es:[17h*4], offset MyInt17
  349.         mov    es:[17h*4+2], cs
  350.         sti                ;Okay, ints back on.
  351.  
  352.  
  353. ; We're hooked up, the only thing that remains is to terminate and
  354. ; stay resident.
  355.  
  356.         print
  357.         byte    "Installed.",cr,lf,0
  358.  
  359.         mov    ah, 62h            ;Get this program's PSP
  360.         int    21h            ; value.
  361.  
  362.         mov    dx, EndResident        ;Compute size of program.
  363.         sub    dx, bx
  364.         mov    ax, 3100h        ;DOS TSR command.
  365.         int    21h
  366. Main        endp
  367. cseg        ends
  368.  
  369. sseg        segment    para stack 'stack'
  370. stk        byte    1024 dup ("stack   ")
  371. sseg        ends
  372.  
  373. zzzzzzseg    segment    para public 'zzzzzz'
  374. LastBytes    byte    16 dup (?)
  375. zzzzzzseg    ends
  376.         end    Main
  377.